package com.ld.poetry.service.impl;

import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ld.poetry.config.PoetryResult;
import com.ld.poetry.constants.CommonConst;
import com.ld.poetry.dao.UserMapper;
import com.ld.poetry.entity.User;
import com.ld.poetry.entity.WebInfo;
import com.ld.poetry.entity.WeiYan;
import com.ld.poetry.enums.PoetryEnum;
import com.ld.poetry.handle.PoetryRuntimeException;
import com.ld.poetry.im.http.dao.ImChatGroupUserMapper;
import com.ld.poetry.im.http.dao.ImChatUserFriendMapper;
import com.ld.poetry.im.http.entity.ImChatGroupUser;
import com.ld.poetry.im.http.entity.ImChatUserFriend;
import com.ld.poetry.im.websocket.ImConfigConst;
import com.ld.poetry.im.websocket.TioUtil;
import com.ld.poetry.im.websocket.TioWebsocketStarter;
import com.ld.poetry.service.UserService;
import com.ld.poetry.service.WeiYanService;
import com.ld.poetry.utils.*;
import com.ld.poetry.utils.cache.PoetryCache;
import com.ld.poetry.utils.mail.MailUtil;
import com.ld.poetry.vo.BaseRequestVO;
import com.ld.poetry.vo.UserVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.tio.core.Tio;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private WeiYanService weiYanService;  // 微言服务，用于处理用户动态

    @Autowired
    private ImChatGroupUserMapper imChatGroupUserMapper;  // 即时通讯群组用户Mapper

    @Autowired
    private ImChatUserFriendMapper imChatUserFriendMapper;  // 即时通讯好友关系Mapper

    @Autowired
    private MailUtil mailUtil;  // 邮件工具类，用于发送验证码等邮件

    @Value("${user.code.format}")
    private String codeFormat;  // 验证码格式配置

    /**
     * 用户登录
     * 处理用户登录请求，包括：
     * 1. 密码解密
     * 2. 账号验证
     * 3. 状态检查
     * 4. Token生成
     * 
     * @param account 用户账号（可以是用户名、邮箱或手机号）
     * @param password 加密后的密码
     * @param isAdmin 是否是管理员登录
     * @return 登录结果，包含用户信息和token
     */
    @Override
    public PoetryResult<UserVO> login(String account, String password, Boolean isAdmin) {
        // 1. 解密前端传来的AES加密密码
        password = new String(SecureUtil.aes(CommonConst.CRYPOTJS_KEY.getBytes(StandardCharsets.UTF_8)).decrypt(password));

        // 2. 查询用户信息
        // 支持通过用户名、邮箱或手机号登录
        User one = lambdaQuery().and(wrapper -> wrapper
                        .eq(User::getUsername, account)
                        .or()
                        .eq(User::getEmail, account)
                        .or()
                        .eq(User::getPhoneNumber, account))
                .eq(User::getPassword, DigestUtils.md5DigestAsHex(password.getBytes()))
                .one();

        // 3. 账号验证
        if (one == null) {
            return PoetryResult.fail("账号/密码错误，请重新输入！");
        }

        // 4. 账号状态检查
        if (!one.getUserStatus()) {
            return PoetryResult.fail("账号被冻结！");
        }

        // 5. 管理员权限检查
        String adminToken = "";
        String userToken = "";
        if (isAdmin) {
            if (one.getUserType() != PoetryEnum.USER_TYPE_ADMIN.getCode() && one.getUserType() != PoetryEnum.USER_TYPE_DEV.getCode()) {
                return PoetryResult.fail("请输入管理员账号！");
            }
            if (PoetryCache.get(CommonConst.ADMIN_TOKEN + one.getId()) != null) {
                adminToken = (String) PoetryCache.get(CommonConst.ADMIN_TOKEN + one.getId());
            }
        } else {
            if (PoetryCache.get(CommonConst.USER_TOKEN + one.getId()) != null) {
                userToken = (String) PoetryCache.get(CommonConst.USER_TOKEN + one.getId());
            }
        }

        // 6. Token生成
        if (isAdmin && !StringUtils.hasText(adminToken)) {
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            adminToken = CommonConst.ADMIN_ACCESS_TOKEN + uuid;
            PoetryCache.put(adminToken, one, CommonConst.TOKEN_EXPIRE);
            PoetryCache.put(CommonConst.ADMIN_TOKEN + one.getId(), adminToken, CommonConst.TOKEN_EXPIRE);
        } else if (!isAdmin && !StringUtils.hasText(userToken)) {
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            userToken = CommonConst.USER_ACCESS_TOKEN + uuid;
            PoetryCache.put(userToken, one, CommonConst.TOKEN_EXPIRE);
            PoetryCache.put(CommonConst.USER_TOKEN + one.getId(), userToken, CommonConst.TOKEN_EXPIRE);
        }

        // 7. 准备返回数据
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(one, userVO);
        userVO.setPassword(null);  // 不返回密码
        if (isAdmin && one.getUserType() == PoetryEnum.USER_TYPE_ADMIN.getCode()) {
            userVO.setIsBoss(true);  // 设置管理员标识
        }

        // 8. 设置token
        if (isAdmin) {
            userVO.setAccessToken(adminToken);
        } else {
            userVO.setAccessToken(userToken);
        }
        return PoetryResult.success(userVO);
    }

    /**
     * 用户退出登录
     * 处理用户退出登录请求，包括：
     * 1. 清理token缓存
     * 2. 清理WebSocket连接
     * 
     * @return 退出结果
     */
    @Override
    public PoetryResult exit() {
        // 获取当前用户的token和ID
        String token = PoetryUtil.getToken();
        Integer userId = PoetryUtil.getUserId();
        
        // 根据token类型清理不同的缓存
        if (token.contains(CommonConst.USER_ACCESS_TOKEN)) {
            // 清理普通用户token
            PoetryCache.remove(CommonConst.USER_TOKEN + userId);
            // 清理WebSocket连接
            TioWebsocketStarter tioWebsocketStarter = TioUtil.getTio();
            if (tioWebsocketStarter != null) {
                Tio.removeUser(tioWebsocketStarter.getServerTioConfig(), String.valueOf(userId), "remove user");
            }
        } else if (token.contains(CommonConst.ADMIN_ACCESS_TOKEN)) {
            // 清理管理员token
            PoetryCache.remove(CommonConst.ADMIN_TOKEN + userId);
        }
        
        // 清理token对应的用户信息缓存
        PoetryCache.remove(token);
        return PoetryResult.success();
    }

    /**
     * 用户注册
     * 处理用户注册请求，包括：
     * 1. 用户名格式验证
     * 2. 联系方式验证
     * 3. 验证码验证
     * 4. 密码处理
     * 5. 重复性检查
     * 6. 用户信息保存
     * 7. Token生成
     * 8. 初始化用户数据
     * 
     * @param user 用户注册信息
     * @return 注册结果，包含用户信息和token
     */
    @Override
    public PoetryResult<UserVO> regist(UserVO user) {
        // 1. 用户名格式验证
        // 1.1 检查用户名是否为11位数字（避免与手机号混淆）
        String regex = "\\d{11}";
        if (user.getUsername().matches(regex)) {
            return PoetryResult.fail("用户名不能为11位数字！");
        }

        // 1.2 检查用户名是否包含@符号（避免与邮箱混淆）
        if (user.getUsername().contains("@")) {
            return PoetryResult.fail("用户名不能包含@！");
        }

        // 2. 联系方式验证
        // 2.1 检查是否同时输入了手机号和邮箱（只能选择一种联系方式）
        if (StringUtils.hasText(user.getPhoneNumber()) && StringUtils.hasText(user.getEmail())) {
            return PoetryResult.fail("手机号与邮箱只能选择其中一个！");
        }

        // 3. 验证码验证
        // 3.1 如果使用手机号注册
        if (StringUtils.hasText(user.getPhoneNumber())) {
            // 从缓存中获取手机验证码
            Integer codeCache = (Integer) PoetryCache.get(CommonConst.FORGET_PASSWORD + user.getPhoneNumber() + "_1");
            // 验证码不存在或错误
            if (codeCache == null || codeCache != Integer.parseInt(user.getCode())) {
                return PoetryResult.fail("验证码错误！");
            }
            // 验证成功后删除验证码
            PoetryCache.remove(CommonConst.FORGET_PASSWORD + user.getPhoneNumber() + "_1");
        } 
        // 3.2 如果使用邮箱注册
        else if (StringUtils.hasText(user.getEmail())) {
            // 从缓存中获取邮箱验证码
            Integer codeCache = (Integer) PoetryCache.get(CommonConst.FORGET_PASSWORD + user.getEmail() + "_2");
            // 验证码不存在或错误
            if (codeCache == null || codeCache != Integer.parseInt(user.getCode())) {
                return PoetryResult.fail("验证码错误！");
            }
            // 验证成功后删除验证码
            PoetryCache.remove(CommonConst.FORGET_PASSWORD + user.getEmail() + "_2");
        } 
        // 3.3 既没有手机号也没有邮箱
        else {
            return PoetryResult.fail("请输入邮箱或手机号！");
        }

        // 4. 密码处理
        // 4.1 解密前端传来的AES加密密码
        user.setPassword(new String(SecureUtil.aes(CommonConst.CRYPOTJS_KEY.getBytes(StandardCharsets.UTF_8)).decrypt(user.getPassword())));

        // 5. 重复性检查
        // 5.1 检查用户名是否已存在
        Integer count = lambdaQuery().eq(User::getUsername, user.getUsername()).count();
        if (count != 0) {
            return PoetryResult.fail("用户名重复！");
        }
        // 5.2 检查手机号是否已存在
        if (StringUtils.hasText(user.getPhoneNumber())) {
            Integer phoneNumberCount = lambdaQuery().eq(User::getPhoneNumber, user.getPhoneNumber()).count();
            if (phoneNumberCount != 0) {
                return PoetryResult.fail("手机号重复！");
            }
        } 
        // 5.3 检查邮箱是否已存在
        else if (StringUtils.hasText(user.getEmail())) {
            Integer emailCount = lambdaQuery().eq(User::getEmail, user.getEmail()).count();
            if (emailCount != 0) {
                return PoetryResult.fail("邮箱重复！");
            }
        }

        // 6. 创建新用户
        User u = new User();
        u.setUsername(user.getUsername());
        u.setPhoneNumber(user.getPhoneNumber());
        u.setEmail(user.getEmail());
        // 6.1 使用MD5加密存储密码
        u.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
        // 6.2 设置随机头像
        u.setAvatar(PoetryUtil.getRandomAvatar(null));
        // 6.3 保存用户信息
        save(u);

        // 7. 获取完整的用户信息
        User one = lambdaQuery().eq(User::getId, u.getId()).one();

        // 8. Token处理
        // 8.1 生成用户token
        String userToken = CommonConst.USER_ACCESS_TOKEN + UUID.randomUUID().toString().replaceAll("-", "");
        // 8.2 将用户信息存入token缓存
        PoetryCache.put(userToken, one, CommonConst.TOKEN_EXPIRE);
        // 8.3 将token存入用户缓存
        PoetryCache.put(CommonConst.USER_TOKEN + one.getId(), userToken, CommonConst.TOKEN_EXPIRE);

        // 9. 准备返回的用户信息
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(one, userVO);
        // 9.1 不返回密码信息
        userVO.setPassword(null);
        // 9.2 设置token
        userVO.setAccessToken(userToken);

        // 10. 初始化用户数据
        // 10.1 创建一条"到此一游"的微言
        WeiYan weiYan = new WeiYan();
        weiYan.setUserId(one.getId());
        weiYan.setContent("到此一游");
        weiYan.setType(CommonConst.WEIYAN_TYPE_FRIEND);
        weiYan.setIsPublic(Boolean.TRUE);
        weiYanService.save(weiYan);

        // 10.2 将用户加入默认群组
        ImChatGroupUser imChatGroupUser = new ImChatGroupUser();
        imChatGroupUser.setGroupId(ImConfigConst.DEFAULT_GROUP_ID);
        imChatGroupUser.setUserId(one.getId());
        imChatGroupUser.setUserStatus(ImConfigConst.GROUP_USER_STATUS_PASS);
        imChatGroupUserMapper.insert(imChatGroupUser);

        // 10.3 建立与站长的双向好友关系
        // 10.3.1 用户->站长
        ImChatUserFriend imChatUser = new ImChatUserFriend();
        imChatUser.setUserId(one.getId());
        imChatUser.setFriendId(PoetryUtil.getAdminUser().getId());
        imChatUser.setRemark("站长");
        imChatUser.setFriendStatus(ImConfigConst.FRIEND_STATUS_PASS);
        imChatUserFriendMapper.insert(imChatUser);

        // 10.3.2 站长->用户
        ImChatUserFriend imChatFriend = new ImChatUserFriend();
        imChatFriend.setUserId(PoetryUtil.getAdminUser().getId());
        imChatFriend.setFriendId(one.getId());
        imChatFriend.setFriendStatus(ImConfigConst.FRIEND_STATUS_PASS);
        imChatUserFriendMapper.insert(imChatFriend);

        // 11. 返回注册结果
        return PoetryResult.success(userVO);
    }

    /**
     * 更新用户信息
     * 处理用户更新个人信息的请求，包括：
     * 1. 用户名格式验证
     * 2. 用户名重复性检查
     * 3. 更新用户信息
     * 4. 更新缓存
     * 
     * @param user 包含要更新的用户信息
     * @return 更新后的用户信息（不包含密码）
     */
    @Override
    public PoetryResult<UserVO> updateUserInfo(UserVO user) {
        // 1. 如果更新用户名，进行格式验证
        if (StringUtils.hasText(user.getUsername())) {
            // 1.1 检查用户名是否为11位数字（避免与手机号混淆）
            String regex = "\\d{11}";
            if (user.getUsername().matches(regex)) {
                return PoetryResult.fail("用户名不能为11位数字！");
            }

            // 1.2 检查用户名是否包含@符号（避免与邮箱混淆）
            if (user.getUsername().contains("@")) {
                return PoetryResult.fail("用户名不能包含@！");
            }

            // 1.3 检查用户名是否与其他用户重复
            Integer count = lambdaQuery().eq(User::getUsername, user.getUsername()).ne(User::getId, PoetryUtil.getUserId()).count();
            if (count != 0) {
                return PoetryResult.fail("用户名重复！");
            }
        }

        // 2. 创建更新对象
        User u = new User();
        u.setId(PoetryUtil.getUserId());  // 设置当前用户ID
        u.setUsername(user.getUsername());  // 更新用户名
        u.setAvatar(user.getAvatar());  // 更新头像
        u.setGender(user.getGender());  // 更新性别
        u.setIntroduction(user.getIntroduction());  // 更新个人简介

        // 3. 执行更新
        updateById(u);

        // 4. 获取更新后的完整用户信息
        User one = lambdaQuery().eq(User::getId, u.getId()).one();

        // 5. 更新缓存
        // 5.1 更新token对应的用户信息缓存
        PoetryCache.put(PoetryUtil.getToken(), one, CommonConst.TOKEN_EXPIRE);
        // 5.2 更新用户ID对应的token缓存
        PoetryCache.put(CommonConst.USER_TOKEN + one.getId(), PoetryUtil.getToken(), CommonConst.TOKEN_EXPIRE);

        // 6. 准备返回数据
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(one, userVO);
        userVO.setPassword(null);  // 不返回密码
        userVO.setAccessToken(PoetryUtil.getToken());  // 设置当前token

        return PoetryResult.success(userVO);
    }

    /**
     * 获取验证码
     * 处理用户获取验证码的请求，包括：
     * 1. 生成6位随机验证码
     * 2. 根据验证码类型（手机/邮箱）发送验证码
     * 3. 将验证码存入缓存
     * 
     * @param flag 验证码类型：1-手机验证码，2-邮箱验证码
     * @return 获取验证码结果
     */
    @Override
    public PoetryResult getCode(Integer flag) {
        // 1. 获取当前用户信息
        User user = PoetryUtil.getCurrentUser();
        
        // 2. 生成6位随机验证码（范围：100000-999999）
        int i = new Random().nextInt(900000) + 100000;
        
        // 3. 根据验证码类型处理
        if (flag == 1) {
            // 3.1 手机验证码处理
            // 检查用户是否已绑定手机号
            if (!StringUtils.hasText(user.getPhoneNumber())) {
                return PoetryResult.fail("请先绑定手机号！");
            }
            // 记录验证码日志
            log.info(user.getId() + "---" + user.getUsername() + "---" + "手机验证码---" + i);
        } else if (flag == 2) {
            // 3.2 邮箱验证码处理
            // 检查用户是否已绑定邮箱
            if (!StringUtils.hasText(user.getEmail())) {
                return PoetryResult.fail("请先绑定邮箱！");
            }
            // 记录验证码日志
            log.info(user.getId() + "---" + user.getUsername() + "---" + "邮箱验证码---" + i);

            // 3.2.1 准备发送邮件
            List<String> mail = new ArrayList<>();
            mail.add(user.getEmail());
            String text = getCodeMail(i);
            WebInfo webInfo = (WebInfo) PoetryCache.get(CommonConst.WEB_INFO);

            // 3.2.2 检查邮件发送次数限制
            AtomicInteger count = (AtomicInteger) PoetryCache.get(CommonConst.CODE_MAIL + mail.get(0));
            if (count == null || count.get() < CommonConst.CODE_MAIL_COUNT) {
                // 发送验证码邮件
                mailUtil.sendMailMessage(mail, "您有一封来自" + (webInfo == null ? "POETIZE" : webInfo.getWebName()) + "的回执！", text);
                
                // 更新发送次数
                if (count == null) {
                    // 首次发送，初始化计数器
                    PoetryCache.put(CommonConst.CODE_MAIL + mail.get(0), new AtomicInteger(1), CommonConst.CODE_EXPIRE);
                } else {
                    // 增加发送次数
                    count.incrementAndGet();
                }
            } else {
                // 超过每日发送限制
                return PoetryResult.fail("验证码发送次数过多，请明天再试！");
            }
        }
        
        // 4. 将验证码存入缓存，5分钟有效期
        PoetryCache.put(CommonConst.USER_CODE + PoetryUtil.getUserId() + "_" + flag, Integer.valueOf(i), 300);
        return PoetryResult.success();
    }

    /**
     * 获取绑定验证码
     * 处理用户绑定手机号或邮箱时获取验证码的请求，包括：
     * 1. 生成6位随机验证码
     * 2. 根据验证码类型（手机/邮箱）发送验证码
     * 3. 将验证码存入缓存
     * 
     * @param place 联系方式（手机号或邮箱地址）
     * @param flag 验证码类型：1-手机验证码，2-邮箱验证码
     * @return 获取验证码结果
     */
    @Override
    public PoetryResult getCodeForBind(String place, Integer flag) {
        // 1. 生成6位随机验证码（范围：100000-999999）
        int i = new Random().nextInt(900000) + 100000;
        
        // 2. 根据验证码类型处理
        if (flag == 1) {
            // 2.1 手机验证码处理
            // 记录验证码日志
            log.info(place + "---" + "手机验证码---" + i);
        } else if (flag == 2) {
            // 2.2 邮箱验证码处理
            // 记录验证码日志
            log.info(place + "---" + "邮箱验证码---" + i);
            
            // 2.2.1 准备发送邮件
            List<String> mail = new ArrayList<>();
            mail.add(place);
            String text = getCodeMail(i);
            WebInfo webInfo = (WebInfo) PoetryCache.get(CommonConst.WEB_INFO);

            // 2.2.2 检查邮件发送次数限制
            AtomicInteger count = (AtomicInteger) PoetryCache.get(CommonConst.CODE_MAIL + mail.get(0));
            if (count == null || count.get() < CommonConst.CODE_MAIL_COUNT) {
                // 发送验证码邮件
                mailUtil.sendMailMessage(mail, "您有一封来自" + (webInfo == null ? "POETIZE" : webInfo.getWebName()) + "的回执！", text);
                
                // 更新发送次数
                if (count == null) {
                    // 首次发送，初始化计数器
                    PoetryCache.put(CommonConst.CODE_MAIL + mail.get(0), new AtomicInteger(1), CommonConst.CODE_EXPIRE);
                } else {
                    // 增加发送次数
                    count.incrementAndGet();
                }
            } else {
                // 超过每日发送限制
                return PoetryResult.fail("验证码发送次数过多，请明天再试！");
            }
        }
        
        // 3. 将验证码存入缓存，5分钟有效期
        // 缓存key格式：USER_CODE + 用户ID + 联系方式 + 验证码类型
        PoetryCache.put(CommonConst.USER_CODE + PoetryUtil.getUserId() + "_" + place + "_" + flag, Integer.valueOf(i), 300);
        return PoetryResult.success();
    }

    /**
     * 更新用户敏感信息
     * 处理用户更新手机号、邮箱或密码的请求，包括：
     * 1. 密码解密和验证
     * 2. 验证码验证
     * 3. 重复性检查
     * 4. 更新用户信息
     * 5. 更新缓存
     * 
     * @param place 联系方式（手机号或邮箱）或旧密码
     * @param flag 操作类型：1-更新手机号，2-更新邮箱，3-更新密码
     * @param code 验证码（更新手机号或邮箱时需要）
     * @param password 新密码（更新密码时需要）
     * @return 更新后的用户信息（不包含密码）
     */
    @Override
    public PoetryResult<UserVO> updateSecretInfo(String place, Integer flag, String code, String password) {
        // 1. 解密前端传来的AES加密密码
        password = new String(SecureUtil.aes(CommonConst.CRYPOTJS_KEY.getBytes(StandardCharsets.UTF_8)).decrypt(password));

        // 2. 获取当前用户信息
        User user = PoetryUtil.getCurrentUser();
        
        // 3. 根据操作类型进行不同的处理
        if ((flag == 1 || flag == 2) && !DigestUtils.md5DigestAsHex(password.getBytes()).equals(user.getPassword())) {
            return PoetryResult.fail("密码错误！");
        }
        if ((flag == 1 || flag == 2) && !StringUtils.hasText(code)) {
            return PoetryResult.fail("请输入验证码！");
        }

        // 4. 创建更新对象
        User updateUser = new User();
        updateUser.setId(user.getId());

        if (flag == 1) {
            // 4.1 更新手机号
            // 4.1.1 检查手机号是否已被其他用户使用
            Integer count = lambdaQuery().eq(User::getPhoneNumber, place).count();
            if (count != 0) {
                return PoetryResult.fail("手机号重复！");
            }
            
            // 4.1.2 验证验证码
            Integer codeCache = (Integer) PoetryCache.get(CommonConst.USER_CODE + PoetryUtil.getUserId() + "_" + place + "_" + flag);
            if (codeCache != null && codeCache.intValue() == Integer.parseInt(code)) {
                // 验证成功后删除验证码
                PoetryCache.remove(CommonConst.USER_CODE + PoetryUtil.getUserId() + "_" + place + "_" + flag);
                // 更新手机号
                updateUser.setPhoneNumber(place);
            } else {
                return PoetryResult.fail("验证码错误！");
            }
        } else if (flag == 2) {
            // 4.2 更新邮箱
            // 4.2.1 检查邮箱是否已被其他用户使用
            Integer count = lambdaQuery().eq(User::getEmail, place).count();
            if (count != 0) {
                return PoetryResult.fail("邮箱重复！");
            }
            
            // 4.2.2 验证验证码
            Integer codeCache = (Integer) PoetryCache.get(CommonConst.USER_CODE + PoetryUtil.getUserId() + "_" + place + "_" + flag);
            if (codeCache != null && codeCache.intValue() == Integer.parseInt(code)) {
                // 验证成功后删除验证码
                PoetryCache.remove(CommonConst.USER_CODE + PoetryUtil.getUserId() + "_" + place + "_" + flag);
                // 更新邮箱
                updateUser.setEmail(place);
            } else {
                return PoetryResult.fail("验证码错误！");
            }
        } else if (flag == 3) {
            // 4.3 更新密码
            // 4.3.1 验证旧密码
            if (DigestUtils.md5DigestAsHex(place.getBytes()).equals(user.getPassword())) {
                // 使用MD5加密存储新密码
                updateUser.setPassword(DigestUtils.md5DigestAsHex(password.getBytes()));
            } else {
                return PoetryResult.fail("密码错误！");
            }
        }

        // 5. 执行更新
        updateById(updateUser);

        // 6. 获取更新后的完整用户信息
        User one = lambdaQuery().eq(User::getId, user.getId()).one();

        // 7. 更新缓存
        // 7.1 更新token对应的用户信息缓存
        PoetryCache.put(PoetryUtil.getToken(), one, CommonConst.TOKEN_EXPIRE);
        // 7.2 更新用户ID对应的token缓存
        PoetryCache.put(CommonConst.USER_TOKEN + one.getId(), PoetryUtil.getToken(), CommonConst.TOKEN_EXPIRE);

        // 8. 准备返回数据
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(one, userVO);
        userVO.setPassword(null);  // 不返回密码
        return PoetryResult.success(userVO);
    }

    /**
     * 忘记密码 - 获取验证码
     * 处理用户忘记密码时获取验证码的请求，包括：
     * 1. 生成6位随机验证码
     * 2. 根据联系方式类型（手机/邮箱）发送验证码
     * 3. 将验证码存入缓存
     * 
     * @param place 联系方式（手机号或邮箱）
     * @param flag 验证码类型：1-手机验证码，2-邮箱验证码
     * @return 获取验证码结果
     */
    @Override
    public PoetryResult getCodeForForgetPassword(String place, Integer flag) {
        // 生成6位随机验证码
        int i = new Random().nextInt(900000) + 100000;
        
        // 根据flag判断是手机验证码还是邮箱验证码
        if (flag == 1) {
            // 手机验证码：记录日志
            log.info(place + "---" + "手机验证码---" + i);
        } else if (flag == 2) {
            // 验证邮箱格式
            if (!place.matches("^[A-Za-z0-9+_.-]+@(.+)$")) {
                return PoetryResult.fail("邮箱格式不正确！");
            }
            
            // 邮箱验证码：记录日志
            log.info(place + "---" + "邮箱验证码---" + i);

            // 发送文件前的准备
            // 创建一个邮件收件人列表
            List<String> mail = new ArrayList<>();
            // 将用户输入的邮箱地址（place）添加到收件人列表中
            mail.add(place);
            // 生成邮件内容，i是6位随机验证码
            String text = getCodeMail(i);
            // 从缓存中获取网站信息（用于在邮件中显示网站名称）
            WebInfo webInfo = (WebInfo) PoetryCache.get(CommonConst.WEB_INFO);

            // 检查该邮箱今日发送验证码次数
            AtomicInteger count = (AtomicInteger) PoetryCache.get(CommonConst.CODE_MAIL + mail.get(0));
            if (count == null || count.get() < CommonConst.CODE_MAIL_COUNT) {
                // 发送邮件
                mailUtil.sendMailMessage(mail, "您有一封来自" + (webInfo == null ? "Black" : webInfo.getWebName()) + "的回执！", text);
                
                // 更新发送次数
                if (count == null) {
                    // 首次发送，初始化计数器
                    PoetryCache.put(CommonConst.CODE_MAIL + mail.get(0), new AtomicInteger(1), CommonConst.CODE_EXPIRE);
                } else {
                    // 增加发送次数
                    count.incrementAndGet();
                }
            } else {
                // 超过每日发送限制
                return PoetryResult.fail("验证码发送次数过多，请明天再试！");
            }
        }
        
        // 将验证码存入缓存，5分钟有效期
        PoetryCache.put(CommonConst.FORGET_PASSWORD + place + "_" + flag, Integer.valueOf(i), 300);
        return PoetryResult.success();
    }

    /**
     * 忘记密码 - 更新密码
     * 处理用户忘记密码后更新密码的请求，包括：
     * 1. 验证码验证
     * 2. 密码解密
     * 3. 用户信息更新
     * 4. 缓存清理
     * 
     * @param place 联系方式（手机号或邮箱）
     * @param flag 验证码类型：1-手机验证码，2-邮箱验证码
     * @param code 用户输入的验证码
     * @param password 加密后的新密码
     * @return 更新密码结果
     */
    @Override
    public PoetryResult updateForForgetPassword(String place, Integer flag, String code, String password) {
        // 1. 解密前端传来的AES加密密码
        password = new String(SecureUtil.aes(CommonConst.CRYPOTJS_KEY.getBytes(StandardCharsets.UTF_8)).decrypt(password));

        // 2. 验证码验证
        Integer codeCache = (Integer) PoetryCache.get(CommonConst.FORGET_PASSWORD + place + "_" + flag);
        if (codeCache == null || codeCache != Integer.parseInt(code)) {
            return PoetryResult.fail("验证码错误！");
        }

        // 3. 验证成功后删除验证码
        PoetryCache.remove(CommonConst.FORGET_PASSWORD + place + "_" + flag);

        // 4. 根据联系方式类型更新密码
        if (flag == 1) {
            // 4.1 手机号方式
            User user = lambdaQuery().eq(User::getPhoneNumber, place).one();
            if (user == null) {
                return PoetryResult.fail("该手机号未绑定账号！");
            }

            if (!user.getUserStatus()) {
                return PoetryResult.fail("账号被冻结！");
            }

            // 更新密码
            lambdaUpdate().eq(User::getPhoneNumber, place)
                .set(User::getPassword, DigestUtils.md5DigestAsHex(password.getBytes()))
                .update();
            // 清理用户缓存
            PoetryCache.remove(CommonConst.USER_CACHE + user.getId().toString());
        } else if (flag == 2) {
            // 4.2 邮箱方式
            User user = lambdaQuery().eq(User::getEmail, place).one();
            if (user == null) {
                return PoetryResult.fail("该邮箱未绑定账号！");
            }

            if (!user.getUserStatus()) {
                return PoetryResult.fail("账号被冻结！");
            }

            // 更新密码
            lambdaUpdate().eq(User::getEmail, place)
                .set(User::getPassword, DigestUtils.md5DigestAsHex(password.getBytes()))
                .update();
            // 清理用户缓存
            PoetryCache.remove(CommonConst.USER_CACHE + user.getId().toString());
        }

        return PoetryResult.success();
    }

    /**
     * 分页查询用户列表
     * 根据条件查询用户列表，包括：
     * 1. 用户状态筛选
     * 2. 用户类型筛选
     * 3. 关键字搜索（用户名/手机号/邮箱）
     * 4. 按创建时间倒序排序
     * 5. 敏感信息脱敏
     * 
     * @param baseRequestVO 查询条件，包含分页参数和筛选条件
     * @return 分页后的用户列表（不包含密码和openId）
     */
    @Override
    public PoetryResult<Page> listUser(BaseRequestVO baseRequestVO) {
        // 1. 创建查询条件
        LambdaQueryChainWrapper<User> lambdaQuery = lambdaQuery();

        // 2. 添加筛选条件
        // 2.1 用户状态筛选
        if (baseRequestVO.getUserStatus() != null) {
            lambdaQuery.eq(User::getUserStatus, baseRequestVO.getUserStatus());
        }

        // 2.2 用户类型筛选
        if (baseRequestVO.getUserType() != null) {
            lambdaQuery.eq(User::getUserType, baseRequestVO.getUserType());
        }

        // 2.3 关键字搜索（用户名/手机号/邮箱）
        if (StringUtils.hasText(baseRequestVO.getSearchKey())) {
            lambdaQuery.and(lq -> lq.like(User::getUsername, baseRequestVO.getSearchKey())
                    .or()
                    .like(User::getPhoneNumber, baseRequestVO.getSearchKey())
                    .or()
                    .like(User::getEmail, baseRequestVO.getSearchKey()));
        }

        // 3. 执行分页查询
        // 3.1 按创建时间倒序排序
        lambdaQuery.orderByDesc(User::getCreateTime);
        // 3.2 执行分页查询
        Page<User> page = new Page<>(baseRequestVO.getCurrent(), baseRequestVO.getSize());
        lambdaQuery.page(page);

        // 4. 敏感信息脱敏
        List<User> records = page.getRecords();
        if (!CollectionUtils.isEmpty(records)) {
            records.forEach(u -> {
                u.setPassword(null);  // 不返回密码
                u.setOpenId(null);    // 不返回openId
            });
        }

        return PoetryResult.success(page);
    }

    /**
     * 根据用户名模糊查询用户列表
     * 处理用户搜索功能，包括：
     * 1. 按用户名模糊查询
     * 2. 限制返回数量
     * 3. 只返回必要字段
     * 4. 数据转换
     * 
     * @param username 用户名关键字
     * @return 最多5个匹配的用户列表（只包含基本信息）
     */
    @Override
    public PoetryResult<List<UserVO>> getUserByUsername(String username) {
        // 1. 执行模糊查询
        // 1.1 只查询必要的字段
        // 1.2 限制返回5条记录
        List<User> users = lambdaQuery()
                .select(User::getId, User::getUsername, User::getAvatar, User::getGender, User::getIntroduction)
                .like(User::getUsername, username)
                .last("limit 5")
                .list();

        // 2. 数据转换
        // 2.1 将User实体转换为UserVO
        List<UserVO> userVOS = users.stream().map(u -> {
            UserVO userVO = new UserVO();
            userVO.setId(u.getId());
            userVO.setUsername(u.getUsername());
            userVO.setAvatar(u.getAvatar());
            userVO.setIntroduction(u.getIntroduction());
            userVO.setGender(u.getGender());
            return userVO;
        }).collect(Collectors.toList());

        return PoetryResult.success(userVOS);
    }

    /**
     * 通过token获取用户信息
     * 处理用户token验证和用户信息获取，包括：
     * 1. token解密
     * 2. token有效性验证
     * 3. 用户信息获取
     * 4. 敏感信息处理
     * 
     * @param userToken 加密后的用户token
     * @return 用户信息（不包含密码）
     * @throws PoetryRuntimeException 当token无效或过期时抛出异常
     */
    @Override
    public PoetryResult<UserVO> token(String userToken) {
        // 1. 解密前端传来的AES加密token
        userToken = new String(SecureUtil.aes(CommonConst.CRYPOTJS_KEY.getBytes(StandardCharsets.UTF_8)).decrypt(userToken));

        // 2. token有效性验证
        if (!StringUtils.hasText(userToken)) {
            throw new PoetryRuntimeException("未登陆，请登陆后再进行操作！");
        }

        // 3. 从缓存中获取用户信息
        User user = (User) PoetryCache.get(userToken);
        if (user == null) {
            throw new PoetryRuntimeException("登录已过期，请重新登陆！");
        }

        // 4. 准备返回数据
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user, userVO);
        userVO.setPassword(null);  // 不返回密码
        userVO.setAccessToken(userToken);  // 设置token

        return PoetryResult.success(userVO);
    }

    /**
     * 订阅/取消订阅标签
     * 处理用户对标签的订阅操作，包括：
     * 1. 获取当前用户信息
     * 2. 解析现有订阅列表
     * 3. 更新订阅状态
     * 4. 更新用户信息
     * 5. 返回更新后的用户信息
     * 
     * @param labelId 标签ID
     * @param flag 操作类型：true-订阅，false-取消订阅
     * @return 更新后的用户信息（不包含密码）
     */
    @Override
    public PoetryResult<UserVO> subscribe(Integer labelId, Boolean flag) {
        // 1. 初始化返回对象
        UserVO userVO = null;
        
        // 2. 获取当前用户信息
        User one = lambdaQuery().eq(User::getId, PoetryUtil.getUserId()).one();
        
        // 3. 解析现有订阅列表
        List<Integer> sub = JSON.parseArray(one.getSubscribe(), Integer.class);
        if (sub == null) {
            sub = new ArrayList<>();
        }
        
        // 4. 根据操作类型处理订阅
        if (flag) {
            // 4.1 订阅操作
            if (!sub.contains(labelId)) {
                // 4.1.1 添加新订阅
                sub.add(labelId);
                
                // 4.1.2 更新用户订阅信息
                User user = new User();
                user.setId(one.getId());
                user.setSubscribe(JSON.toJSONString(sub));
                updateById(user);

                // 4.1.3 准备返回数据
                userVO = new UserVO();
                BeanUtils.copyProperties(one, userVO);
                userVO.setPassword(null);  // 不返回密码
                userVO.setSubscribe(user.getSubscribe());  // 设置更新后的订阅列表
                userVO.setAccessToken(PoetryUtil.getToken());  // 设置当前token
            }
        } else {
            // 4.2 取消订阅操作
            if (sub.contains(labelId)) {
                // 4.2.1 移除订阅
                sub.remove(labelId);
                
                // 4.2.2 更新用户订阅信息
                User user = new User();
                user.setId(one.getId());
                user.setSubscribe(JSON.toJSONString(sub));
                updateById(user);

                // 4.2.3 准备返回数据
                userVO = new UserVO();
                BeanUtils.copyProperties(one, userVO);
                userVO.setPassword(null);  // 不返回密码
                userVO.setSubscribe(user.getSubscribe());  // 设置更新后的订阅列表
                userVO.setAccessToken(PoetryUtil.getToken());  // 设置当前token
            }
        }
        
        return PoetryResult.success(userVO);
    }

    /**
     * 获取验证码邮件内容
     * 生成包含验证码的邮件内容模板
     * 
     * @param i 6位随机验证码
     * @return 格式化后的邮件内容
     */
    private String getCodeMail(int i) {
        // 获取网站信息，用于显示网站名称
        WebInfo webInfo = (WebInfo) PoetryCache.get(CommonConst.WEB_INFO);
        // 如果获取不到网站信息，使用默认名称"black"
        String webName = (webInfo == null ? "black" : webInfo.getWebName());
        
        // 使用String.format格式化邮件模板
        return String.format(mailUtil.getMailText(),
                webName,  // 网站名称
                String.format(MailUtil.imMail, PoetryUtil.getAdminUser().getUsername()),  // 邮件类型
                PoetryUtil.getAdminUser().getUsername(),  // 管理员用户名
                String.format(codeFormat, i),  // 验证码
                "",  // 空字符串（可能是预留的额外内容）
                webName);  // 再次使用网站名称
    }
}
